home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / HS.C < prev    next >
Text File  |  1993-08-09  |  17KB  |  665 lines

  1. /* Interface driver for the DRSI PCPA or the Eagle 8530 boards for the IBM PC
  2.  * connected to a WA4DSY 56kbps modem. Uses polling-loop transfers with
  3.  * interrupts disabled for maximum speed.
  4.  *
  5.  * This driver is a bit of a kludge. A DMA-driven card and driver (e.g.,
  6.  * the PI) is much better, but this is better than nothing if all you have
  7.  * is a "dumb" 8530 card.
  8.  *
  9.  * Copyright 1991 Phil Karn, KA9Q
  10.  */
  11. #include <stdio.h>
  12. #include <dos.h>
  13. #include "global.h"
  14. #include "config.h"
  15. #ifdef HS
  16. #include "mbuf.h"
  17. #include "iface.h"
  18. #include "pktdrvr.h"
  19. #include "netuser.h"
  20. #include "hs.h"
  21. #include "n8530.h"
  22. #include "ax25.h"
  23. #include "trace.h"
  24. #include "pc.h"
  25. #include "proc.h"
  26. #include "kiss.h"
  27. #include "devparam.h"
  28.  
  29. static void flushrx __ARGS((int16 data));
  30. static void hdlcparam __ARGS((struct hdlc *hp));
  31. static void hexint __ARGS((struct hdlc *hp));
  32. static void hrxint __ARGS((struct hdlc *hp));
  33. static int hs_stop __ARGS((struct iface *iface,int temp));
  34. static int hs_raw __ARGS((struct iface *iface,struct mbuf *bp));
  35. static void hs_tx __ARGS((int unused,void *hp1,void *a));
  36. static int32 hs_ctl __ARGS((struct iface *,int cmd,int set,int32 val));
  37. static void hstxoff __ARGS((struct hdlc *hp));
  38. static void hstxon __ARGS((struct hdlc *hp));
  39. static void htxint __ARGS((struct hdlc *hp));
  40. static void init_delay __ARGS((void));
  41. static void msdelay __ARGS((void));
  42.  
  43. static struct hs Hs[NHS];
  44. static INTERRUPT (*Hshandle[])() = { hs0vec };
  45. static struct hdlc Hdlc[2*NHS];
  46. static int16 Nhs;
  47.  
  48. /* Master interrupt handler for the PC-100 card. All interrupts come
  49.  * here first, then are switched out to the appropriate routine.
  50.  */
  51. void
  52. hsint(int dev)
  53. {
  54.     char iv;
  55.     struct hdlc *hp;
  56.  
  57.     int16 hsbase = Hs[dev].addr;
  58.     Hs[dev].ints++;
  59.  
  60. #ifdef    foo
  61.     outportb(hsbase+4,0x8+0x10);    /* HIT EAGLE INTACK */
  62.     (void)inportb(hsbase+CHANA+CTL,R0);
  63.     outportb(hsbase+4,0x8);        /***/
  64. #endif
  65.  
  66.     /* Read interrupt status from channel A */
  67.     while((iv = read_scc(hsbase+CHANA+CTL,R3)) != 0){
  68.         if(iv & CHARxIP){
  69.             /* Channel A Rcv Interrupt Pending */
  70.             hp = &Hdlc[2*dev];
  71.             hrxint(hp);
  72.         } else if(iv & CHATxIP){
  73.             /* Channel A Transmit Int Pending */
  74.             hp = &Hdlc[2*dev];
  75.             htxint(hp);
  76.         } else if(iv & CHAEXT){
  77.             /* Channel A External Status Int */
  78.             hp = &Hdlc[2*dev];
  79.             hexint(hp);
  80.         } else if(iv & CHBRxIP){
  81.             /* Channel B Rcv Interrupt Pending */
  82.             hp = &Hdlc[(2*dev)+1];
  83.             hrxint(hp);
  84.         } else if(iv & CHBTxIP){
  85.             /* Channel B Transmit Int Pending */
  86.             hp = &Hdlc[(2*dev)+1];
  87.             htxint(hp);
  88.         } else if(iv & CHBEXT){
  89.             /* Channel B External Status Int */
  90.             hp = &Hdlc[(2*dev)+1];
  91.             hexint(hp);
  92.         }
  93.         /* Reset interrupt pending state */
  94.         write_scc(hp->ctl,R0,RES_H_IUS);
  95.         outportb(hsbase+CHANA+CTL,0);    /* Restore pointer to 0 */
  96.         outportb(hsbase+CHANB+CTL,0);    /* Restore pointer to 0 */
  97.     }
  98.     outportb(hsbase+CHANA+CTL,0);    /* Restore pointer to 0 */
  99.     outportb(hsbase+CHANB+CTL,0);    /* Restore pointer to 0 */
  100. }
  101.  
  102. /* HDLC SIO External/Status interrupts
  103.  * The only one that can happen in this driver is a DCD change
  104.  */
  105. static void
  106. hexint(struct hdlc *hp)
  107. {
  108.     struct mbuf *rcvbuf;
  109.     struct phdr phdr;
  110.     char *cp;
  111.     int cnt = 0, ctl = hp->ctl, data = hp->data;
  112.  
  113.     hp->exints++;
  114.  
  115.     /* Allocate a receive buffer */
  116.     if((rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(struct phdr))) == NULLBUF){
  117.         /* Alloc failed; refuse to proceed */
  118.         hp->nomem++;
  119.         write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  120.         write_scc(ctl,R0,RES_EXT_INT);
  121.         return;
  122.     }
  123.     /* Allow space for phdr descriptor on front */
  124.     cp = rcvbuf->data + sizeof(struct phdr);
  125.  
  126.     /* Disable DCDIE bit so we can track changes in DCD */
  127.     write_scc(ctl,R15,0);
  128.  
  129.     write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  130.     flushrx(data);
  131.     while((cnt = rx8530(ctl,data,cp,hp->bufsiz)) != -1){
  132.         if(cnt > 4){
  133.             /* Good frame */
  134.             hp->good++;
  135.             /* Toss crc */
  136.             rcvbuf->cnt = sizeof(struct phdr) + cnt - 1;
  137.             phdr.iface = hp->iface;
  138.             phdr.type = CL_AX25;
  139.             memcpy(rcvbuf->data,(char *)&phdr,sizeof(struct phdr));
  140.             enqueue(&Hopper,rcvbuf);
  141.             /* Replenish buffer */
  142.             rcvbuf = alloc_mbuf(hp->bufsiz + sizeof(struct phdr));
  143.         }
  144.         /* Start new buffer */
  145.         if(rcvbuf == NULLBUF)
  146.             break;    /* alloc failed */
  147.         cp = rcvbuf->data + sizeof(struct phdr);
  148.     }
  149.     write_scc(ctl,R0,RES_EXT_INT);
  150.     write_scc(ctl,R15,DCDIE);    /* Re-enable DCD */
  151.     write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  152.  
  153.     /* Get rid of fragmentary buffer */
  154.     free_p(rcvbuf);
  155. }
  156.  
  157. static void
  158. flushrx(int16 data)
  159. {
  160.     int i = 5;
  161.  
  162.     while(i-- != 0)
  163.         inportb(data);
  164. }
  165.  
  166. /* HDLC receiver interrupt handler.
  167.  * Not used in this driver
  168.  */
  169. static void
  170. hrxint(struct hdlc *hp)
  171. {
  172. }
  173.  
  174. /* HDLC transmit interrupt service routine
  175.  * Not used in this driver
  176.  */
  177. static void
  178. htxint(struct hdlc *hp)
  179. {
  180. }
  181.  
  182. /* (re)Initialize HDLC controller parameters */
  183. static void
  184. hdlcparam(struct hdlc *hp)
  185. {
  186.     /* Initialize 8530 channel for SDLC operation */
  187.     int16 ctl = hp->ctl;
  188.  
  189.     DISABLE();
  190.  
  191. #ifdef    foo
  192.     switch(ctl & 2){
  193.     case CHANA:
  194.         write_scc(ctl,R9,CHRA);    /* Reset channel A */
  195.         break;
  196.     case CHANB:
  197.         write_scc(ctl,R9,CHRB);    /* Reset channel B */
  198.         break;
  199.     }
  200.     pause(1L);    /* Allow plenty of time for resetting */
  201. #endif
  202.  
  203.     /* Deselect interrupts for now */
  204.     write_scc(ctl,R1,0);
  205.     write_scc(ctl,R15,0);
  206.  
  207.     /* X1 clock, SDLC mode, Sync modes enable, parity disable */
  208.     write_scc(ctl,R4,X1CLK | SDLC | SYNC_ENAB);
  209.  
  210.     /* CRC preset 1, NRZ encoding, no active on poll, flag idle,
  211.      * flag on underrun, no loop mode, 8 bit sync
  212.      */
  213.     write_scc(ctl,R10,CRCPS|NRZ);
  214.  
  215.     /* 8530 gets both tx and rx clock from modem.
  216.      * By default, TRxC = transmit clock, RTxC = receive clock
  217.      * (swapped 11 Feb 1990 to use new DRSI wiring) UNLESS
  218.      * the 'r' parameter is specified
  219.      */
  220.     if(!hp->clkrev)
  221.         write_scc(ctl,R11,RCRTxCP | TCTRxCP);
  222.     else
  223.         write_scc(ctl,R11,RCTRxCP | TCRTxCP);
  224.  
  225.     /* Note: baud rate generator not used */
  226.  
  227.     /* Null out SDLC start address */
  228.     write_scc(ctl,R6,0);
  229.  
  230.     /* SDLC flag */
  231.     write_scc(ctl,R7,FLAG);
  232.  
  233.     /* DTR On, 8 bit TX chars, no break, TX enable, SDLC CRC,
  234.      * RTS off, TxCRC enable
  235.      */
  236.     write_scc(ctl,R5,DTR|Tx8|TxENAB|TxCRC_ENAB);
  237.  
  238.     /* 8 bit RX chars, auto enables off, no hunt mode, RxCRC enable,
  239.      * no address search, no inhibit sync chars, disable RX. Rx is
  240.      * started only by an actual DCD interrupt
  241.      */
  242.     write_scc(ctl,R3,RxENABLE|RxCRC_ENAB|Rx8);
  243.  
  244.     /* Dummy interrupt vector
  245.      * (This probably isn't necessary)
  246.      */
  247.     write_scc(ctl,R2,0);
  248.  
  249.     /* Enable only the external interrupts (modem interrupts) since
  250.      * polling is used for all actual tx/rx operations
  251.      */
  252.     write_scc(ctl,R1,EXT_INT_ENAB);
  253.  
  254.     /* Enable only DCD interrupts */
  255.     write_scc(ctl,R15,DCDIE);
  256.  
  257.     /* No reset, status low, master int enable, enable lower chain,
  258.      * no vector
  259.      */
  260.     write_scc(ctl,R9,MIE|NV);
  261.  
  262.     RESTORE();
  263. }
  264.  
  265. /* Attach a high speed iterface to the system
  266.  * argv[0]: hardware type, must be "hs"
  267.  * argv[1]: I/O address, e.g., "0x380"
  268.  * argv[2]: vector, e.g., "2"
  269.  * argv[3]: mode, must be "ax25"
  270.  * argv[4]: interface base label, e.g., "drsi0". Driver appends "a" and "b".
  271.  * argv[5]: receiver packet buffer size in bytes
  272.  * argv[6]: maximum transmission unit, bytes
  273.  * argv[7]: keyup delay, milliseconds
  274.  * argv[8]: persistence value, 0-255
  275.  * argv[9]: "r" to reverse sense of clock leads (optional)
  276.  */
  277. int
  278. hs_attach(int argc,char **argv,void *p)
  279. {
  280.     struct iface *if_hsa, *if_hsb;
  281.     struct hdlc *hp;
  282.     int dev;
  283.  
  284.     if(*Mycall == '\0') {
  285.         tputs(Nomycall);
  286.         return -1;
  287.     }
  288.     if(stricmp(argv[3],"AX25") != 0) {
  289.         tputs("Mode must be ax25\n");
  290.         return -1;
  291.     }
  292.     if(if_lookup(argv[4]) != NULLIF){
  293.         tprintf(Ifexist,argv[4]);
  294.         return -1;
  295.     }
  296.     if(Nhs >= NHS){
  297.         tprintf("Max %d HS controller/s\n",NHS);
  298.         return -1;
  299.     }
  300.     dev = Nhs++;
  301.  
  302.     /* Initialize hardware-level control structure */
  303.     Hs[dev].addr = htoi(argv[1]);
  304.     Hs[dev].vec = htoi(argv[2]);
  305.  
  306.     /* Save original interrupt vector */
  307.     Hs[dev].save.vec = getirq(Hs[dev].vec);
  308.     /* Set new interrupt vector */
  309.     if(setirq(Hs[dev].vec,Hshandle[dev]) == -1){
  310.         tprintf("IRQ %u out of range\n",Hs[dev].vec);
  311.         Nhs--;
  312.         return -1;
  313.     }
  314.     /* Create interface structures and fill in details */
  315.     if_hsa = mxallocw(sizeof(struct iface));
  316.     if_hsb = mxallocw(sizeof(struct iface));
  317.  
  318.     if_hsa->addr = if_hsb->addr = Ip_addr;
  319.     if_hsa->name = strxdup(argv[4]);
  320.     if_hsa->name = if_name(if_hsa,"a");
  321.     if_hsb->name = strxdup(argv[4]);
  322.     if_hsb->name = if_name(if_hsb,"b");
  323.     if_hsb->mtu = if_hsa->mtu = atoi(argv[6]);
  324.     if_hsb->type = if_hsa->type = CL_AX25;
  325.     if_hsa->dev = 2*dev;
  326.     if_hsb->dev = 2*dev + 1;
  327.     if_hsb->stop = if_hsa->stop = hs_stop;
  328.     if_hsb->output = if_hsa->output = ax_output;
  329.     if_hsb->raw = if_hsa->raw = hs_raw;
  330.     if_hsa->ioctl = if_hsb->ioctl = hs_ctl;
  331.  
  332.     if_hsb->send = if_hsa->send = ax_send;
  333.  
  334.     if_hsa->hwaddr = strxdup(Mycall);
  335.     if_hsb->hwaddr = strxdup(Mycall);
  336.  
  337.     if_hsa->next = if_hsb;
  338.     if_hsb->next = Ifaces;
  339.     Ifaces = if_hsa;
  340.     if_hsa->niface = Niface++;
  341.     if_hsb->niface = Niface++;
  342.  
  343.     write_scc(Hs[dev].addr+CHANA+CTL,R9,FHWRES);
  344.     hp = &Hdlc[2*dev+1];
  345.     hp->ctl = Hs[dev].addr + CHANB + CTL;
  346.     hp->data = Hs[dev].addr + CHANB + DATA;
  347.     hp->bufsiz = atoi(argv[5]);
  348.     hp->txdelay = (argc > 7) ? atoi(argv[7]) : 15;
  349.     hp->persist = (argc > 8) ? atoi(argv[8]) : 64;
  350.     hp->clkrev = (argc > 9 && argv[9][0] == 'r') ? 1 : 0;
  351.     hp->iface = if_hsb;
  352.     hdlcparam(hp);
  353.     if_hsa->proc1 = newproc("hs_tx",1024,hs_tx,0,hp,NULL,0);
  354.  
  355.     hp = &Hdlc[2*dev];
  356.     hp->ctl = Hs[dev].addr + CHANA + CTL;
  357.     hp->data = Hs[dev].addr + CHANA + DATA;
  358.     hp->bufsiz = atoi(argv[5]);
  359.     hp->txdelay = Hdlc[2*dev+1].txdelay;
  360.     hp->persist = Hdlc[2*dev+1].persist;
  361.     hp->clkrev = (argc > 9 && argv[9][0] == 'r') ? 1 : 0;
  362.     hp->iface = if_hsa;
  363.     hdlcparam(hp);
  364.     if_hsb->proc1 = newproc("hs_tx",1024,hs_tx,0,hp,NULL,0);
  365.  
  366.     outportb(Hs[dev].addr + 4,0x08);    /*EAGLE INT GATE */
  367.     /* Clear mask (enable interrupt) in 8259 interrupt controller */
  368.     maskon(Hs[dev].vec);
  369.  
  370.     /* Initialize timing delay loop */
  371.     init_delay();
  372.     return 0;
  373. }
  374.  
  375. static int
  376. hs_stop(struct iface *iface,int temp)
  377. {
  378.     int dev = iface->dev;
  379.  
  380.     if(dev & 1)
  381.         return -1;    /* Valid only for the first device */
  382.  
  383.     dev >>= 1;    /* Convert back into hs number */
  384.  
  385.     /* Turn off interrupts */
  386.     maskoff(Hs[dev].vec);
  387.  
  388.     /* Restore original interrupt vector */
  389.     setirq(Hs[dev].vec,Hs[dev].save.vec);
  390.  
  391.     /* Force hardware reset */
  392.     write_scc(Hs[dev].addr + CHANA+CTL,R9,FHWRES);
  393.     return 0;
  394. }
  395.  
  396. /* Send raw packet */
  397. static int
  398. hs_raw(struct iface *iface,struct mbuf *bp)
  399. {
  400.     struct hdlc *hp = &Hdlc[iface->dev];
  401.  
  402.     dump(iface,IF_TRACE_OUT,CL_AX25,bp);
  403.  
  404.     hp->txpkts++;
  405.     enqueue(&hp->txq,bp);    /* Put on queue for hs_tx process */
  406.     return 0;
  407. }
  408.  
  409. /* High speed transmit process */
  410. void
  411. hs_tx(int unused,void *hp1,void *a)
  412. {
  413.     struct mbuf *bp,*nbp;
  414.     char *cp;
  415.     int cnt, i, txon = 0;    /* Transmitter on/off state */
  416.  
  417.     struct hdlc *hp = (struct hdlc *)hp1;
  418.     int16 ctl = hp->ctl;
  419.     int16 data = hp->data;
  420.  
  421.     for(;;){
  422.         /* Wait for work */
  423.         while(hp->txq == NULLBUF){
  424.             if(txon){
  425.                 /* No more frames, shut down tx */
  426.                 hstxoff(hp);
  427.                 txon = 0;
  428.                 /* Hold off to give other guy a chance to
  429.                  * respond
  430.                  */
  431.                 hp->deftime = msclock() + hp->txdelay + 500;
  432.             }
  433.             pwait(&hp->txq);
  434.         }
  435.         bp = dequeue(&hp->txq);
  436.         cnt = len_p(bp);
  437.         /* If buffer isn't contiguous (which is almost always
  438.          * the case) copy it to a new buffer for speed
  439.          */
  440.         if(bp->next != NULLBUF){
  441.             if((nbp = copy_p(bp,cnt)) == NULLBUF){
  442.                 hp->nomem++;
  443.                 free_p(bp);
  444.                 continue;
  445.             }
  446.             free_p(bp);
  447.             bp = nbp;
  448.         }
  449.         cp = bp->data;
  450.         /* Turn transmitter on if necessary */
  451.         if(!txon){
  452.             hstxon(hp);
  453.             txon = 1;
  454.         } else {
  455.             /* Else wait another txd for receiver to get ready again */
  456.             for(i=(int)hp->txdelay;i != 0;i--)
  457.                 msdelay();
  458.         }
  459.         /* Initialize transmitter CRC */
  460.         write_scc(ctl,R0,RES_Tx_CRC);
  461.         for(;;){
  462.             /* Wait for the transmitter to become ready */
  463.             while(!(inportb(ctl) & Tx_BUF_EMP))
  464.                 ;
  465.             if(cnt-- == 0)
  466.                 break;
  467.             outportb(data,*cp++); /* Send the character */
  468.         }
  469.         write_scc(ctl,R0,RES_EOM_L);    /* Allow CRC generation */
  470.  
  471.         /* End of frame. Wait for TxEOM to go high, indicating start of
  472.          * CRC transmission. Note that we don't reset the transmit
  473.          * interrupt pending flag as one ordinarily would, since we're
  474.          * not using tx interrupts.
  475.          */
  476.         while(!(inportb(ctl) & TxEOM))
  477.             ;
  478.  
  479.         free_p(bp);
  480.     }
  481. }
  482.  
  483. /* Turn on high speed transmitter. Does p-persistence, then sends a dummy
  484.  * frame to allow for keyup delay. Returns with transmitter on and interrupts
  485.  * disabled
  486.  */
  487. static void
  488. hstxon(struct hdlc *hp)
  489. {
  490.     int i;
  491.     long ca;
  492.     int32 t;
  493.  
  494.     int16 ctl = hp->ctl;
  495.  
  496.     /* Defer logic. Wait until deftime is in the past (so we
  497.      * defer to any overheard CTS messages) AND the p-persistence
  498.      * dice roll succeeds. The computation of ca allows for clock
  499.      * rollover (which happens every 49+ days).
  500.      */
  501.     for(;;){
  502.         t = msclock();
  503.         ca = hp->deftime - t;
  504.         if(ca > 0){
  505.             pause(ca);
  506.             continue;
  507.         }
  508.         hp->deftime = t;    /* Keep from getting too old */
  509.         if((rand() & 0xff) > uchar(hp->persist)){
  510.             pause((long)MSPTICK);
  511.             continue;
  512.         }
  513.         break;
  514.     }
  515.     /* Prevent distractions. In particular, block off the DCD interrupt
  516.      * so we don't hear our own carrier and hang in the interrupt handler!
  517.      * Note that simply disabling CPU interrupts isn't enough since
  518.      * the call to pause will block and the kernel will re-enable
  519.      * them.
  520.      */
  521.     write_scc(ctl,R9,0);    /* Disable all SCC interrupts */
  522.     DISABLE();
  523.  
  524.     /* Turn on carrier, enable transmitter */
  525.     write_scc(ctl,R5,TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR);
  526.  
  527.     /* Delay for keyup interval */
  528.     for(i=(int)hp->txdelay;i != 0;i--)
  529.         msdelay();
  530.  
  531. }
  532. /* Turn transmitter off at the end of a series of frames */
  533. static void
  534. hstxoff(struct hdlc *hp)
  535. {
  536.     int cnt;
  537.  
  538.     int16 ctl = hp->ctl;
  539.     int16 data = hp->data;
  540.  
  541.     /* To allow the SCC buffering to drain, we begin a dummy frame,
  542.      * then abort it
  543.      */
  544.     for(cnt = 5; cnt != 0; cnt--) {
  545.         while(!(inportb(ctl) & Tx_BUF_EMP))
  546.             ;
  547.         outportb(data,0);
  548.     }
  549.     write_scc(ctl,R0,SEND_ABORT);
  550.  
  551.     /* Turn off carrier and disable transmitter */
  552.     write_scc(ctl,R5,TxCRC_ENAB | Tx8 | DTR);
  553.     /* Re-Enable SCC interrupts */
  554.     write_scc(ctl,R9,MIE|NV);
  555.     restore(1);    /* Turn interrupts back on */
  556. }
  557.  
  558. int
  559. dohs(int argc,char **argv,void *p)
  560. {
  561.     int i;
  562.  
  563.     for(i = 0; i < 2 * Nhs; i++) {
  564.         struct hdlc *hp = &Hdlc[i];
  565.         tprintf("port %d: txpkts %lu ints %lu rxpkts %lu rxbytes %lu nomem %lu toobig %lu crcerr %lu aborts %lu overrun %lu\n",
  566.             i,
  567.             hp->txpkts,
  568.             hp->exints,
  569.             hp->good,
  570.             hp->rxbytes,
  571.             hp->nomem,
  572.             hp->toobig,
  573.             hp->crcerr,
  574.             hp->aborts,
  575.             hp->overrun);
  576.     }
  577.     return 0;
  578. }
  579.  
  580. static int32
  581. hs_ctl(struct iface *iface,int cmd,int set,int32 val)
  582. {
  583.     int32 t, ca;
  584.  
  585.     struct hdlc *hp = &Hdlc[iface->dev];
  586.  
  587.     switch(cmd){
  588.     case PARAM_TXDELAY:    /* Tx keyup delay */
  589.         if(set)
  590.             hp->txdelay = (int)val;
  591.         return hp->txdelay;
  592.     case PARAM_PERSIST:
  593.         if(set)
  594.             hp->persist = (int)val;
  595.         return hp->persist;
  596.     case PARAM_MUTE:
  597.         /* Mute transmitter for specified # of ms */
  598.         if(set) {
  599.             if(val == -1){
  600.                 /* Special case for duration of a CTS */
  601.                 val = hp->txdelay + 500;
  602.             }
  603.             hp->deftime = msclock() + val;
  604.         }
  605.         t = msclock();
  606.         ca = hp->deftime - t;
  607.         if(ca < 0){
  608.             hp->deftime = t;
  609.             ca = 0;
  610.         }
  611.         return ca;
  612.     }
  613.     return -1;
  614. }
  615.  
  616. static int32 Del_const;
  617.  
  618. /* Find the value of Del_const that will cause one execution of mloop()
  619.  * to take one millisecond
  620.  */
  621. static void
  622. init_delay(void)
  623. {
  624.     int32 start,delay;
  625.     int i, j, success = 0;
  626.  
  627.     /* Start with small value to make things tolerable on slow machines */
  628.     Del_const = 10;
  629.  
  630.     tprintf("Del_const = %lu\n",Del_const);
  631.  
  632.     /* Limit the number of iterations in case we don't converge */
  633.     for(i = 0; i < 5; i++) {
  634.         start = msclock();
  635.         for(j = 0; j < 1000; j++)
  636.             msdelay();
  637.         delay = msclock() - start;
  638.         tprintf("delay %lu\n",delay);
  639.         if(delay == 0){
  640.             /* Too fast for accurate measurement on coarse clk */
  641.             Del_const *= 10;
  642.             tprintf("Del_const = %lu\n",Del_const);
  643.             continue;
  644.         }
  645.         Del_const = (Del_const * 1000)/delay;
  646.         tprintf("Del_const = %lu\n",Del_const);
  647.         if(delay > 950 && delay < 1050){
  648.             success = 1;
  649.             break;    /* Within 1 tick - Close enough */
  650.         }
  651.     }
  652.     if(!success)
  653.         tputs("HS: Warning: auto delay set failed\n");
  654. }
  655.  
  656. /* Delay for one millisecond (once calibrated by init_delay()) */
  657. static void
  658. msdelay(void)
  659. {
  660.     int32 i;
  661.  
  662.     for(i = Del_const; i != 0; i--)    ;
  663. }
  664.  
  665. #endif /* HS */